//! WAL（Write-Ahead Logging）系统单元测试
//!
//! 测试WAL日志的写入、持久化和恢复功能

use super::transaction::{WalManager, WalRecordType, TransactionManager, IsolationLevel};
use super::page::{PageManager, PageType};
use crate::{Result, Error};
use std::sync::Arc;
use tempfile::TempDir;
use std::time::Instant;

#[cfg(test)]
mod tests {
    use super::*;

    /// 测试WAL管理器的基本功能
    #[test]
    fn test_wal_manager_basic() -> Result<()> {
        let temp_dir = TempDir::new()
            .map_err(|e| Error::storage(format!("创建临时目录失败: {}", e)))?;
        let wal_path = temp_dir.path().join("test.wal").to_string_lossy().to_string();

        let wal_manager = WalManager::new(wal_path)?;

        // 测试事务开始记录
        wal_manager.write_transaction_begin(1)?;
        
        // 测试数据变更记录
        let insert_record = WalRecordType::Insert {
            page_id: 100,
            slot_id: 0,
            old_data: None,
            new_data: vec![1, 2, 3, 4, 5],
        };
        wal_manager.write_record(1, insert_record)?;

        let update_record = WalRecordType::Update {
            page_id: 100,
            slot_id: 0,
            old_data: vec![1, 2, 3, 4, 5],
            new_data: vec![6, 7, 8, 9, 10],
        };
        wal_manager.write_record(1, update_record)?;

        // 测试事务提交记录
        wal_manager.write_transaction_commit(1)?;

        // 刷新到磁盘
        wal_manager.flush()?;

        // 验证LSN递增（通过检查WAL文件大小）
        let wal_file_path = temp_dir.path().join("test.wal");
        let file_size = std::fs::metadata(&wal_file_path)
            .map_err(|e| Error::storage(format!("获取WAL文件大小失败: {}", e)))?
            .len();
        assert!(file_size > 0);

        Ok(())
    }

    /// 测试WAL恢复功能
    #[test]
    fn test_wal_recovery() -> Result<()> {
        let temp_dir = TempDir::new()
            .map_err(|e| Error::storage(format!("创建临时目录失败: {}", e)))?;
        let wal_path = temp_dir.path().join("recovery_test.wal").to_string_lossy().to_string();
        let page_file = temp_dir.path().join("recovery_pages.db");

        // 第一阶段：写入WAL记录
        {
            let page_manager = Arc::new(PageManager::with_disk_storage(50, &page_file)?);
            let tx_manager = TransactionManager::new(page_manager.clone(), wal_path.clone())?;

            // 创建事务并写入数据
            let tx = tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
            let page_id = page_manager.allocate_page(PageType::Data)?;

            // 写入WAL记录
            let record = WalRecordType::Insert {
                page_id,
                slot_id: 0,
                old_data: None,
                new_data: vec![0xAA, 0xBB, 0xCC, 0xDD],
            };
            tx_manager.get_wal_manager().write_record(tx.id, record)?;

            tx_manager.commit_transaction(tx)?;
            tx_manager.get_wal_manager().flush()?;
        }

        // 第二阶段：模拟重启和恢复
        {
            let page_manager = Arc::new(PageManager::with_disk_storage(50, &page_file)?);
            let tx_manager = TransactionManager::new(page_manager.clone(), wal_path)?;

            // 执行恢复
            tx_manager.recover()?;

            // 验证恢复后可以正常操作
            let tx = tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
            let page_id = page_manager.allocate_page(PageType::Data)?;
            tx_manager.commit_transaction(tx)?;

            assert!(page_id > 0);
        }

        Ok(())
    }

    /// 测试WAL记录序列化和反序列化
    #[test]
    fn test_wal_record_serialization() -> Result<()> {
        let temp_dir = TempDir::new()
            .map_err(|e| Error::storage(format!("创建临时目录失败: {}", e)))?;
        let wal_path = temp_dir.path().join("serialization_test.wal").to_string_lossy().to_string();

        let wal_manager = WalManager::new(wal_path)?;

        // 测试不同类型的WAL记录
        let records = vec![
            WalRecordType::TransactionBegin,
            WalRecordType::Insert {
                page_id: 1,
                slot_id: 0,
                old_data: None,
                new_data: vec![1, 2, 3],
            },
            WalRecordType::Update {
                page_id: 1,
                slot_id: 0,
                old_data: vec![1, 2, 3],
                new_data: vec![4, 5, 6],
            },
            WalRecordType::Delete {
                page_id: 1,
                slot_id: 0,
                old_data: vec![4, 5, 6],
            },
            WalRecordType::TransactionCommit,
        ];

        // 写入所有记录
        for (i, record) in records.iter().enumerate() {
            wal_manager.write_record(1, record.clone())?;
        }

        wal_manager.flush()?;

        // 验证记录数量（通过检查WAL文件大小）
        let wal_file_path = temp_dir.path().join("serialization_test.wal");
        let file_size = std::fs::metadata(&wal_file_path)
            .map_err(|e| Error::storage(format!("获取WAL文件大小失败: {}", e)))?
            .len();
        assert!(file_size > 0);

        Ok(())
    }

    /// 测试WAL性能
    #[test]
    fn test_wal_performance() -> Result<()> {
        let temp_dir = TempDir::new()
            .map_err(|e| Error::storage(format!("创建临时目录失败: {}", e)))?;
        let wal_path = temp_dir.path().join("performance_test.wal").to_string_lossy().to_string();

        let wal_manager = WalManager::new(wal_path)?;

        let num_records = 1000;
        let start_time = Instant::now();

        // 批量写入WAL记录
        for i in 0..num_records {
            wal_manager.write_transaction_begin(i)?;
            
            let record = WalRecordType::Insert {
                page_id: i,
                slot_id: 0,
                old_data: None,
                new_data: vec![1, 2, 3, 4, 5],
            };
            wal_manager.write_record(i, record)?;
            
            wal_manager.write_transaction_commit(i)?;
        }

        let write_time = start_time.elapsed();
        
        // 刷新到磁盘
        let flush_start = Instant::now();
        wal_manager.flush()?;
        let flush_time = flush_start.elapsed();

        println!("WAL性能测试结果:");
        println!("  写入 {} 条记录耗时: {:?}", num_records * 3, write_time);
        println!("  平均每条记录: {:?}", write_time / (num_records * 3) as u32);
        println!("  刷新到磁盘耗时: {:?}", flush_time);

        // 验证性能要求（每条记录应该在1ms以内）
        let avg_per_record = write_time / (num_records * 3) as u32;
        assert!(avg_per_record.as_millis() < 1, "WAL写入性能不达标");

        Ok(())
    }

    /// 测试WAL错误处理
    #[test]
    fn test_wal_error_handling() -> Result<()> {
        // 测试无效路径
        let invalid_path = "/invalid/path/test.wal".to_string();
        let result = WalManager::new(invalid_path);
        assert!(result.is_err());

        Ok(())
    }

    /// 测试WAL校验和验证
    #[test]
    fn test_wal_checksum_validation() -> Result<()> {
        let temp_dir = TempDir::new()
            .map_err(|e| Error::storage(format!("创建临时目录失败: {}", e)))?;
        let wal_path = temp_dir.path().join("checksum_test.wal").to_string_lossy().to_string();

        let wal_manager = WalManager::new(wal_path)?;

        // 写入记录
        let record = WalRecordType::Insert {
            page_id: 1,
            slot_id: 0,
            old_data: None,
            new_data: vec![1, 2, 3, 4, 5],
        };
        wal_manager.write_record(1, record)?;
        wal_manager.flush()?;

        // 验证校验和计算（简化验证）
        let test_data = vec![1, 2, 3, 4, 5];
        let checksum = test_data.iter().fold(0u32, |acc, &byte| acc.wrapping_add(byte as u32));
        assert_eq!(checksum, 15); // 1+2+3+4+5 = 15

        Ok(())
    }

    /// 测试并发WAL写入
    #[test]
    fn test_concurrent_wal_writes() -> Result<()> {
        let temp_dir = TempDir::new()
            .map_err(|e| Error::storage(format!("创建临时目录失败: {}", e)))?;
        let wal_path = temp_dir.path().join("concurrent_test.wal").to_string_lossy().to_string();

        let wal_manager = Arc::new(WalManager::new(wal_path)?);

        // 模拟并发写入
        let handles: Vec<_> = (0..10).map(|i| {
            let wal_manager = wal_manager.clone();
            std::thread::spawn(move || -> Result<()> {
                for j in 0..10 {
                    let tx_id = i * 10 + j;
                    wal_manager.write_transaction_begin(tx_id)?;
                    
                    let record = WalRecordType::Insert {
                        page_id: tx_id,
                        slot_id: 0,
                        old_data: None,
                        new_data: vec![i as u8, j as u8],
                    };
                    wal_manager.write_record(tx_id, record)?;
                    
                    wal_manager.write_transaction_commit(tx_id)?;
                }
                Ok(())
            })
        }).collect();

        // 等待所有线程完成
        for handle in handles {
            handle.join().unwrap()?;
        }

        wal_manager.flush()?;

        // 验证所有记录都被写入（通过检查WAL文件大小）
        let wal_file_path = temp_dir.path().join("concurrent_test.wal");
        let file_size = std::fs::metadata(&wal_file_path)
            .map_err(|e| Error::storage(format!("获取WAL文件大小失败: {}", e)))?
            .len();
        assert!(file_size > 1000); // 应该有大量数据

        Ok(())
    }
}
